home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v8n15.arc / EMSCACHE.ASM < prev    next >
Assembly Source File  |  1989-08-31  |  35KB  |  854 lines

  1.         title   EMSCACHE Expanded Memory Disk Cache
  2.         page    55,132
  3. ;
  4. ; EMSCACHE.ASM Expanded Memory Disk Cache
  5. ; Copyright (C) 1989 Ziff Davis Communications
  6. ; PC Magazine * Ray Duncan
  7. ; Also requires ITOA.ASM, ATOI.ASM, ARGV.ASM, ARGC.ASM
  8. ;
  9. ; To build:     MASM ITOA;
  10. ;               MASM ATOI;
  11. ;               MASM ARGV;
  12. ;               MASM ARGC;
  13. ;               MASM EMSCACHE;
  14. ;               LINK EMSCACHE+ITOA+ATOI+ARGV+ARGC;
  15. ;               EXE2BIN EMSCACHE.EXE EMSCACHE.COM
  16. ;               DEL EMSCACHE.EXE
  17. ;
  18. ; To install:   EMSCACHE nnn <Enter>
  19. ;               where nnn is the number of KB of expanded
  20. ;               memory to allocate for cache (default=all)
  21.  
  22. cr      equ     0dh                     ; ASCII carriage return
  23. lf      equ     0ah                     ; ASCII line feed
  24. cmdtail equ     80h                     ; command tail offset in PSP
  25. envptr  equ     2ch                     ; pointer to environment block
  26. bpp     equ     16384                   ; bytes per EMS page
  27. bps     equ     512                     ; bytes per sector
  28. spp     equ     bpp/bps                 ; sectors per page
  29.  
  30. _TEXT   segment word public 'CODE'
  31.  
  32.         extrn   atoi:near               ; ASCII to binary integer
  33.         extrn   itoa:near               ; binary integer to ASCII
  34.         extrn   argv:near               ; get ptr to command line arg
  35.         extrn   argc:near               ; get no. of command line args  
  36.  
  37.         org     100h
  38.         assume  cs:_TEXT
  39. entry:  jmp     init                    ; initial entry from MS-DOS
  40.  
  41.         even
  42. old13h  dd      0                       ; previous owner of Int 13H
  43. maxsec  db      0                       ; maximum sector number
  44. maxhead db      0                       ; maximum head number
  45. totalp  dw      0                       ; EMS pages installed
  46. availp  dw      0                       ; EMS pages available
  47. ownedp  dw      0                       ; EMS pages allocated by cache
  48. ixpages dw      0                       ; cache index length in pages
  49. ixbytes dw      0                       ; cache index length in bytes
  50. ixptr   dw      0                       ; cache index search start point
  51. ixhigh  dw      0                       ; cache index highwater mark
  52. pframe  dw      0                       ; segment address of page frame
  53. handle  dw      0                       ; expanded memory handle
  54. sectors dw      0                       ; sectors to transfer
  55. mapped3 dw      0                       ; last map to physical page 3
  56.  
  57. ident   db      cr,lf,lf
  58.         db      'EMSCACHE Expanded Memory Disk Cache 1.0'
  59.         db      cr,lf
  60.         db      'Copyright (C) 1989 Ziff Davis Communications'
  61.         db      cr,lf
  62.         db      'PC Magazine * Ray Duncan'
  63.         db      cr,lf,lf
  64. ident1  db      '       Kbytes expanded memory installed.'
  65.         db      cr,lf
  66. ident2  db      '       Kbytes expanded memory available.'
  67.         db      cr,lf
  68. ident3  db      '       Kbytes assigned to cache.'
  69.         db      cr,lf,0
  70.  
  71. emmname db      'EMMXXXX0',0            ; logical device name for 
  72.                                         ; expanded memory manager
  73.  
  74. ermsg   db      cr,lf
  75.         db      'EMSCACHE installation error:'
  76.         db      cr,lf,0
  77. msg1    db      'program already resident.'
  78.         db      cr,lf,0
  79. msg2    db      'expanded memory manager not found.'
  80.         db      cr,lf,0
  81. msg3    db      'expanded memory not functional.'
  82.         db      cr,lf,0
  83. msg4    db      'expanded memory manager error.'
  84.         db      cr,lf,0
  85. msg5    db      'insufficient expanded memory pages available.'
  86.         db      cr,lf,0
  87. msg6    db      'expanded memory allocation failed.'
  88.         db      cr,lf,0
  89. msg7    db      'wrong expanded memory manager version.'
  90.         db      cr,lf,0
  91. msg8    db      'unable to initialize EMS cache pages.'
  92.         db      cr,lf,0
  93. msg9    db      cr,lf
  94.         db      'EMSCACHE: fatal mapping error.'
  95.         db      cr,lf,0
  96.  
  97.         even
  98. appmap  db      256 dup (0)             ; app mapping context saved here
  99. mymap   db      256 dup (0)             ; initial EMSCACHE mapping context
  100.  
  101. ; The routine 'intr' receives control whenever an application or the 
  102. ; MS-DOS kernel issues a Int 13H call to the ROM BIOS disk driver.
  103. ; Int 13H requests for floppy disks, or for fixed disk operations
  104. ; other than simple reads (AH=2) or writes (AH=3) are simply passed 
  105. ; on to the ROM BIOS without prejudice.
  106.  
  107.         assume  cs:_TEXT,ds:NOTHING,es:NOTHING,ss:NOTHING
  108.  
  109. intr    proc    far
  110.  
  111.         cmp     dl,80h                  ; physical fixed disk 0?
  112.         jne     intr1                   ; no, skip it
  113.         cmp     ah,2                    ; read request?
  114.         je      intr2                   ; yes, process it
  115.         cmp     ah,3                    ; write request?
  116.         je      intr2                   ; yes, process it
  117.  
  118. intr1:  jmp     old13h                  ; let ROM BIOS handle it
  119.  
  120. intr2:  push    ax                      ; save caller's registers 
  121.         push    bx
  122.         push    cx
  123.         push    dx
  124.         push    si
  125.         push    di
  126.         push    bp
  127.         push    ds
  128.         push    es
  129.         mov     bp,sp                   ; set up stack frame
  130.  
  131. regES   equ     [bp]                    ; equates to caller's registers
  132. regDS   equ     [bp+2]                  ; saved in stack frame
  133. regBP   equ     [bp+4]
  134. regDI   equ     [bp+6]
  135. regSI   equ     [bp+8]
  136. regDX   equ     [bp+10]
  137. regCX   equ     [bp+12]
  138. regBX   equ     [bp+14]
  139. regAX   equ     [bp+16]
  140. regAL   equ     [bp+16]
  141. regAH   equ     [bp+17]
  142. regIP   equ     [bp+18]
  143. regCS   equ     [bp+20]
  144. regFLAG equ     [bp+22]
  145.  
  146.         mov     ax,cs                   ; make our data addressable
  147.         mov     ds,ax
  148.         mov     es,ax
  149.         cld                             ; safety first
  150.  
  151.         assume  cs:_TEXT,ds:_TEXT,es:_TEXT
  152.  
  153.         mov     ax,4e02h                ; save caller's mapping context
  154.         mov     si,offset mymap         ; and initialize our context
  155.         mov     di,offset appmap        ; so cache index is accessable
  156.         int     67h
  157.         or      ah,ah
  158.         jnz     crash                   ; jump if lethal mapping error
  159.         mov     mapped3,3               ; init mapping page 3 record
  160.  
  161.         cmp     byte ptr regAH,2        ; read or write?
  162.         jne     intr3                   ; jump if was write
  163.  
  164.         call    read                    ; carry out the read    
  165.         jmp     intr4
  166.  
  167. intr3:  call    write                   ; carry out the write
  168.  
  169. intr4:  push    cs                      ; make our data addressable again
  170.         pop     ds
  171.         mov     ax,4e01h                ; restore caller's mapping context
  172.         mov     si,offset appmap
  173.         int     67h
  174.         or      ah,ah
  175.         jnz     crash                   ; jump if lethal mapping error
  176.  
  177.         pop     es                      ; restore caller's registers
  178.         pop     ds
  179.         pop     bp
  180.         pop     di
  181.         pop     si
  182.         pop     dx
  183.         pop     cx
  184.         pop     bx
  185.         pop     ax
  186.         iret                            ; back to caller        
  187.  
  188. intr    endp
  189.  
  190. ; Come here if catastrophic EMS mapping error during Int 13H service.
  191. ; Display message using ROM BIOS video driver then freeze system.
  192.  
  193. crash   proc    near
  194.  
  195.         mov     si,offset msg9          ; display message
  196.         call    pmsg                    ; "fatal mapping error"
  197.         jmp     $                       ; wait for Ctrl-Alt-Del!
  198.  
  199. crash   endp
  200.  
  201. ; Carry out cached disk read operation.  For single-sector reads,
  202. ; we either deliver the data from cache, or let ROM BIOS read the
  203. ; sector then make a copy for the cache.  For multisector reads,
  204. ; which are much faster when passed to the controller as a unit,
  205. ; we only try to deliver from cache on a sector-by-sector basis
  206. ; if first sector of the group is already in the cache.
  207.  
  208. read    proc    near
  209.  
  210.         push    regBX                   ; save original parameters
  211.         push    regCX
  212.         push    regDX
  213.         push    regES
  214.  
  215.         mov     ax,regAX                ; get number of sectors
  216.         and     ax,0ffh
  217.         jz      read7                   ; jump, zero sectors requested
  218.         mov     sectors,ax
  219.  
  220.         call    find                    ; first or only sector in cache?
  221.         jnc     read4                   ; yes, do it sector by sector
  222.  
  223.         call    rombios                 ; possible multisector read
  224.         or      ah,ah                   ; was read OK?
  225.         jnz     read8                   ; jump, read failed
  226.  
  227. read1:  call    find                    ; this sector in cache?
  228.         jnc     read2                   ; yes, jump 
  229.         call    assign                  ; no, assign a slot
  230.         call    wcache                  ; copy sector to cache
  231.  
  232. read2:  dec     sectors                 ; count sectors
  233.         jz      read7                   ; jump if all sectors cached
  234.         call    bump                    ; advance sector address
  235.         cmp     ixbytes,bpp*3           ; cache index > 3 pages?
  236.         jna     read1                   ; no, index is intact
  237.         call    rest3                   ; restore cache index
  238.         jmp     read1                   ; continue with next sector
  239.  
  240. read3:  call    find                    ; this sector in cache?
  241.         jc      read5                   ; no, jump
  242.  
  243. read4:  call    rcache                  ; copy from cache to caller
  244.         jmp     read6                   ; go do next sector
  245.  
  246. read5:  mov     word ptr regAX,0201h    ; read 1 sector using ROM BIOS
  247.         call    rombios
  248.         or      ah,ah                   ; successful read?
  249.         jnz     read8                   ; read error, give up
  250.         call    assign                  ; get a cache slot
  251.         call    wcache                  ; put sector into cache
  252.  
  253. read6:  dec     sectors                 ; count sectors transferred
  254.         jz      read7                   ; jump, all done
  255.         call    bump                    ; advance sector address
  256.         cmp     ixbytes,bpp*3           ; cache index > 3 pages?
  257.         jna     read3                   ; no, index is intact
  258.         call    rest3                   ; restore cache index
  259.         jmp     read3                   ; continue with next sector
  260.  
  261. read7:  mov     byte ptr regAH,0        ; return AH = 0 for success
  262.         push    regFLAG                 ; & clear caller's carry flag
  263.         popf
  264.         clc
  265.         pushf
  266.         pop     regFLAG
  267.  
  268. read8:  pop     regES                   ; restore original parameters
  269.         pop     regDX                   ; and return
  270.         pop     regCX
  271.         pop     regBX
  272.         ret
  273.  
  274. read    endp
  275.  
  276. ; Carry out cached write operation.  For safety's sake we always
  277. ; demand physical write from ROM BIOS first, then update cache
  278. ; as appropriate.
  279.  
  280. write   proc    near
  281.  
  282.         push    regBX                   ; save original parameters
  283.         push    regCX
  284.         push    regDX
  285.         push    regES
  286.  
  287.         push    regAX                   ; save number of sectors
  288.         call    rombios                 ; call ROM BIOS to write disk
  289.         pop     ax                      ; get back number of sectors
  290.         and     ax,0ffh                 ; zero requested?
  291.         jz      write9                  ; yes, exit
  292.         mov     sectors,ax              ; save number transferred
  293.  
  294. write1: call    find                    ; this sector in cache?
  295.         jc      write2                  ; no, jump
  296.         call    wcache                  ; update data in cache
  297.  
  298. write2: dec     sectors                 ; count sectors
  299.         jz      write9                  ; exit, all sectors checked
  300.         call    bump                    ; advance sector address
  301.         cmp     ixbytes,bpp*3           ; cache index > 3 pages?
  302.         jna     write1                  ; no, index is intact
  303.         call    rest3                   ; restore cache index
  304.         jmp     write1                  ; continue with next sector
  305.  
  306. write9: pop     regES                   ; restore original parameters
  307.         pop     regDX                   ; and return
  308.         pop     regCX
  309.         pop     regBX
  310.         ret
  311.  
  312. write   endp
  313.  
  314. ; Read sector from cache into caller's buffer.
  315. ; Call with:    AX = cache slot
  316. ; Returns:      nothing
  317.  
  318. rcache  proc    near
  319.  
  320.         push    ds
  321.         call    mapsec                  ; map in cache sector
  322.         mov     si,ax                   ; DS:SI = source address
  323.         mov     ds,pframe               ;         in EMS page frame
  324.         mov     di,regBX                ; ES:DI = destination address
  325.         mov     es,regES                ;         in caller's buffer
  326.         mov     cx,bps/2                ; length in words
  327.         rep movsw                       ; copy sector to caller
  328.         pop     ds
  329.         ret                             
  330.  
  331. rcache  endp
  332.  
  333. ; Write sector from caller's buffer into cache.
  334. ; Call with:    AX = cache slot
  335. ; Returns:      nothing
  336.  
  337. wcache  proc    near
  338.  
  339.         push    ds
  340.         call    mapsec                  ; map in cache sector
  341.         mov     di,ax                   ; ES:DI = destination address
  342.         mov     es,pframe               ;         in cache
  343.         mov     si,regBX                ; DS:SI = source address
  344.         mov     ds,regES                ;         in caller's buffer
  345.         mov     cx,bps/2                ; length in words       
  346.         rep movsw                       ; copy sector to cache
  347.         pop     ds
  348.         ret
  349.  
  350. wcache  endp
  351.  
  352. ; Search for matching cache index entry.  Assumes that cache
  353. ; index pages are already mapped in.  The index consists of
  354. ; 4-byte entries which are just the physical sector, head, 
  355. ; cylinder, and drive for the associated cache position.  The
  356. ; high bit of the drive byte is used as the "hit" bit since
  357. ; it is not needed to specify the drive.  If an index position
  358. ; is all zero bytes, it has never been used (a sector number
  359. ; of zero never occurs).
  360. ; Call with:    DS = segment _TEXT
  361. ; Returns:      ES = EMS page frame
  362. ;               (If match found)
  363. ;               Carry = false
  364. ;               AX = cache index slot number
  365. ;               (If no match found)
  366. ;               Carry = true
  367. ;               AX = undefined
  368.  
  369. find    proc    near                    
  370.  
  371.         mov     es,pframe               ; let ES:BX point to
  372.         xor     bx,bx                   ; base of cache index 
  373.         mov     ax,regCX                ; get caller's parameters
  374.         mov     dx,regDX
  375.         and     dx,0ff7fh               ; strip fixed-disk bit
  376.         mov     cx,ixhigh               ; get index highwater mark
  377.  
  378. find1:  cmp     ax,es:[bx]              ; compare sector, cylinder
  379.         je      find3
  380.  
  381. find2:  add     bx,4                    ; advance through cache index
  382.         cmp     bx,cx                   ; reached end yet?
  383.         jna     find1                   ; no
  384.         stc                             ; indicate no cache hit
  385.         ret
  386.  
  387. find3:  mov     di,es:[bx+2]
  388.         and     di,0ff7fh               ; strip hit bit
  389.         cmp     di,dx                   ; compare drive, head
  390.         jne     find2                   ; jump, found match
  391.  
  392.         or      byte ptr es:[bx+2],80h  ; set hit bit
  393.         mov     ax,bx                   ; return cache slot number
  394.         shr     ax,1
  395.         shr     ax,1
  396.         clc                             ; indicate cache hit
  397.         ret
  398.  
  399. find    endp
  400.  
  401. ; Assign a cache slot for sector storage.  Assumes that cache 
  402. ; index pages are already mapped in.
  403. ; Call with:    DS = segment _TEXT
  404. ; Returns:      AX = slot number
  405. ;               ES = EMS page frame
  406.  
  407. assign  proc    near
  408.  
  409.         mov     bx,ixptr                ; starting point for search
  410.         mov     cx,regCX                ; caller's parameters to
  411.         mov     dx,regDX                ; identify sector
  412.         and     dx,0ff7fh               ; strip the drive/hit bit
  413.         mov     es,pframe               ; make page frame addressable
  414.  
  415. asn1:   test    byte ptr es:[bx+2],80h  ; hit bit off?
  416.         jz      asn4                    ; yes, use this slot
  417.         add     bx,4                    ; look at next slot
  418.         cmp     bx,ixbytes              ; time to wrap?
  419.         jne     asn2                    ; not yet
  420.         xor     bx,bx                   ; wrap index pointer
  421.  
  422. asn2:   cmp     bx,ixptr                ; back to where we started?
  423.         jne     asn1                    ; not yet
  424.         xor     bx,bx                   ; init. cache index pointer
  425.  
  426. asn3:   and     byte ptr es:[bx+2],7fh  ; turn off all hit bits
  427.         add     bx,4                     
  428.         cmp     bx,ixbytes              ; end of cache index?
  429.         jne     asn3                    ; not yet, loop
  430.         mov     bx,ixptr                ; start search over,
  431.         jmp     asn1                    ; guaranteed to succeed now
  432.  
  433. asn4:   mov     es:[bx],cx              ; found slot with hit bit off
  434.         mov     es:[bx+2],dx            ; put sector id stuff into it
  435.         cmp     ixhigh,bx               ; set highwater mark for find
  436.         jae     asn5
  437.         mov     ixhigh,bx
  438.  
  439. asn5:   mov     ax,bx                   ; return slot number
  440.         shr     ax,1
  441.         shr     ax,1
  442.  
  443.         add     bx,4                    ; bump starting pointer 
  444.         cmp     bx,ixbytes
  445.         jne     asn6
  446.         xor     bx,bx                   ; wrap if necessary
  447.  
  448. asn6:   mov     ixptr,bx                ; save pointer for next time
  449.         ret
  450.  
  451. assign  endp
  452.  
  453. ; Makes cache sector available by mapping in the appropriate
  454. ; EMS page and returning the offset of the sector within the page.
  455. ; We always use physical page 3 so we can avoid remapping index
  456. ; on multisector transfer if index is less than 4 pages long.
  457. ; Called with:  AX    = cache slot number
  458. ; Returns:      AX    = offset within EMS page frame
  459.  
  460. mapsec  proc    near    
  461.  
  462.         mov     dx,0                    ; divide cache slot number
  463.         mov     cx,spp                  ; by sectors/EMS page to get
  464.         div     cx                      ; AX = logical page
  465.         push    dx                      ; DX = sector within page
  466.         mov     bx,ax
  467.         add     bx,ixpages              ; skip over index pages
  468.         cmp     mapped3,bx              ; page already mapped?
  469.         je      map1                    ; yes, can skip mapping
  470.         mov     mapped3,bx              ; save most recent mapping
  471.         mov     ax,4403h                ; select physical page 3
  472.         mov     dx,handle                
  473.         int     67h                     ; map in the EMS page
  474.         or      ah,ah                   
  475.         jnz     map2                    ; jump if mapping error
  476. map1:   pop     ax                      ; relative sector * 
  477.         mov     cx,bps                  ; bytes / sector = 
  478.         mul     cx                      ; offset in EMS page
  479.         add     ax,(bpp*3)              ; offset to page 4
  480.         ret
  481.  
  482. map2:   jmp     crash                   ; unrecoverable mapping error
  483.  
  484. mapsec  endp
  485.  
  486. ; Restore mapping of logical page 3 to physical page 3.  Only 
  487. ; needed after a sector mapping if cache index requires 4 EMS 
  488. ; pages (i.e. ixbytes > bpp*3).
  489. ; Call with:    nothing
  490. ; Returns:      EMM status in AH
  491.  
  492. rest3   proc    near
  493.  
  494.         mov     ax,4403h                ; map physical page 3
  495.         mov     bx,3                    ; logical page 3
  496.         mov     mapped3,bx              ; save mapping also
  497.         mov     dx,handle               ; our EMM handle
  498.         int     67h
  499.         or      ah,ah                   ; check mapping status
  500.         jnz     rest3a                  
  501.         ret                             ; return, mapping was OK
  502.  
  503. rest3a: jmp     crash                   ; unrecoverable mapping error
  504.  
  505. rest3   endp
  506.  
  507. ; Request Int 13H function from ROM BIOS, using parameters
  508. ; from the stack frame.
  509. ; Call with:    Nothing
  510. ; Returns:      ROM BIOS status in AX
  511. ;               AX and carry flag also placed in caller's 
  512. ;               registers on stack frame.
  513.  
  514. rombios proc    near
  515.  
  516.         mov     ax,regAX                ; read/write, no. of sectors
  517.         mov     bx,regBX                ; buffer offset
  518.         mov     cx,regCX                ; sector, cylinder
  519.         mov     dx,regDX                ; drive, head
  520.         mov     es,regES                ; buffer segment
  521.         pushf                           ; simulate software interrupt 
  522.         call    old13h                  ; transfer to ROM BIOS
  523.         pushf                           ; put away returned status 
  524.         pop     regFLAG                 ; in caller's flags and AX
  525.         mov     regAX,ax
  526.         ret                             
  527.  
  528. rombios endp
  529.  
  530. ; Bump sector, head, and cylinder to next consecutive address.
  531. ; Call with:    nothing
  532. ; Returns:      nothing (values in stack frame altered)
  533.  
  534. bump    proc    near
  535.  
  536.         add     word ptr regES,bps/16   ; increment buffer address
  537.  
  538.         mov     cx,regCX                ; get sector, cylinder
  539.         mov     dx,regDX                ; get head, drive
  540.  
  541.         inc     cl                      ; advance current sector
  542.         mov     al,cl
  543.         and     al,3fh
  544.         cmp     al,maxsec               ; reached end of track?
  545.         jna     bump1                   ; no, jump
  546.  
  547.         and     cl,0c0h                 ; reset to first sector
  548.         add     cl,1                    ; preserving high cyl. bits
  549.  
  550.         inc     dh                      ; advance current head
  551.         cmp     dh,maxhead              ; used all heads?
  552.         jna     bump1                   ; no, jump
  553.  
  554.         xor     dh,dh                   ; reset to first head
  555.  
  556.         inc     ch                      ; increment cylinder
  557.         jnz     bump1                   ; jump if no carry needed
  558.         add     cl,40h                  ; carry cylinder high bits
  559.  
  560. bump1:  mov     regCX,cx                ; put updated sector, head
  561.         mov     regDX,dx                ; cylinder back in stack frame
  562.         ret
  563.  
  564. bump    endp
  565.  
  566. ; Display message using ROM BIOS video driver (since DOS might
  567. ; not be in a stable state).
  568. ; Call with:    DS:SI = address of ASCIIZ string
  569. ; Returns:      nothing
  570.  
  571. pmsg    proc    near
  572.  
  573.         lodsb                           ; get next character
  574.         or      al,al                   ; check for terminating null
  575.         jz      pmsg1                   ; found end of string
  576.         mov     ah,0eh                  ; function 0eh = TTY write char
  577.         mov     bh,0                    ; page = 0
  578.         mov     bl,7                    ; if graphics, color = white
  579.         push    si
  580.         int     10h                     ; transfer to BIOS video driver
  581.         pop     si
  582.         jmp     pmsg
  583.  
  584. pmsg1:  ret                             
  585.  
  586. pmsg    endp
  587.  
  588. ; Initialization routine, called at program load time.  Returns
  589. ; address of 'init' label to MS-DOS as start of free memory, so
  590. ; that memory occupied by 'init' and its subroutines is reclaimed.
  591.  
  592.         assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  593.  
  594. init    proc    near
  595.  
  596.         xor     ax,ax                   ; is EMSCACHE already loaded?
  597.         mov     es,ax                   ; use Int 13H vector to check
  598.         mov     es,es:[(13h*4)+2]       ; for EMSCACHE sign-on msg
  599.         mov     si,offset ident
  600.         mov     di,si
  601.         mov     cx,offset ident1 - offset ident
  602.         cld
  603.         repz cmpsb
  604.         jnz     init1                   ; not previously loaded, proceed
  605.         mov     dx,offset msg1          ; EMSCACHE already resident, exit
  606.         jmp     init_err
  607.  
  608. init1:  xor     ax,ax                   ; is EMM driver present?
  609.         mov     es,ax                   ; use Int 67H vector to check
  610.         mov     es,es:[(67h*4)+2]       ; for EMM driver header
  611.         mov     di,10                   ; ES:DI = addr of device name field
  612.         mov     si,offset emmname       ; DS:SI = expected EMM name
  613.         mov     cx,8                    ; length of device name field
  614.         cld
  615.         repz cmpsb                      ; compare EMM name to driver header
  616.         jz      init2                   ; EMM is present, proceed
  617.         mov     dx,offset msg2          ; no EMM found, exit
  618.         jmp     init_err
  619.  
  620. init2:  push    ds                      ; restore ES = our data
  621.         pop     es
  622.         mov     ah,40h                  ; test EMM status
  623.         int     67h
  624.         or      ah,ah
  625.         jz      init3                   ; driver is OK, proceed
  626.         mov     dx,offset msg3          ; bad status from driver, exit
  627.         jmp     init_err
  628.  
  629. init3:  mov     ah,46h                  ; check EMM version
  630.         int     67h
  631.         or      ah,ah
  632.         jz      init5                   ; got version ok, proceed
  633.  
  634. init4:  mov     dx,offset msg4          ; general EMM error, exit
  635.         jmp     init_err
  636.  
  637. init5:  cmp     al,032h                 ; demand version 3.2 or later
  638.         jae     init6                   ; version is OK, proceed
  639.         mov     dx,offset msg7          ; EMM version too early, exit
  640.         jmp     init_err
  641.  
  642. init6:  mov     ah,41h                  ; get page frame segment
  643.         int     67h
  644.         or      ah,ah
  645.         jnz     init4                   ; jump if EMM error
  646.         mov     pframe,bx               ; save segment of page frame
  647.  
  648.         mov     ah,42h                  ; get number of available pages
  649.         int     67h
  650.         or      ah,ah
  651.         jnz     init4                   ; jump if EMM error
  652.         mov     totalp,dx               ; save total EMM pages
  653.         mov     availp,bx               ; save available EMM pages
  654.         cmp     bx,4                    ; must be at least 4 pages
  655.         jae     init7
  656.         mov     dx,offset msg5          ; insufficient pages, exit
  657.         jmp     init_err
  658.  
  659. init7:  mov     bx,cmdtail              ; ES:BX = command tail
  660.         call    argc                    ; get number of command
  661.         cmp     ax,2                    ; tail arguments
  662.         mov     ax,availp               ; if no arguments, use all
  663.         jl      init9                   ; available pages
  664.  
  665.         mov     ax,1                    ; get address of command
  666.         call    argv                    ; tail argument #1 into ES:BX
  667.         mov     si,bx                   
  668.         call    atoi                    ; convert KB to binary
  669.  
  670.         mov     dx,ax                   ; save copy of KB
  671.         mov     cx,4                    ; divide KB by 16 to get no.
  672.         shr     ax,cl                   ; of EMS pages to request
  673.         and     dx,0fh                  ; round up needed?
  674.         jz      init8                   ; no
  675.         inc     ax                      ; yes
  676.  
  677. init8:  cmp     ax,availp               ; compare with pages available
  678.         jna     init9                   ; jump if ok
  679.         mov     ax,availp               ; request too large, use available
  680.  
  681. init9:  cmp     ax,4                    ; must own at least 64 KB
  682.         jae     init10                  ; (4 pages)
  683.         mov     ax,4
  684.  
  685. init10: cmp     ax,512                  ; but we can't handle more 
  686.         jna     init11                  ; than 8192 KB (512 pages)
  687.         mov     ax,512
  688.  
  689. init11: mov     ownedp,ax               ; save total pages we will own
  690.         mov     bx,ax
  691.         mov     ah,43h                  ; try and allocate EMM pages
  692.         int     67h
  693.         or      ah,ah
  694.         jz      init12                  ; jump, allocation successful
  695.         mov     dx,offset msg6          ; allocation failed, exit
  696.         jmp     init_err
  697.  
  698. init12: mov     handle,dx               ; save EMM handle 
  699.  
  700.         mov     ax,ownedp               ; total pages / sectors/page
  701.         xor     dx,dx                   ; / 4 bytes/index entry
  702.         mov     cx,spp*4                ; = pages required for index
  703.         div     cx
  704.         or      dx,dx                   ; any remainder?
  705.         jz      init13
  706.         inc     ax                      ; round up if necessary 
  707.  
  708. init13: mov     ixpages,ax              ; save pages in cache index
  709.  
  710.         mov     ax,ownedp               ; pages left for sector storage
  711.         sub     ax,ixpages              ; * sectors/page 
  712.         mov     cx,spp*4                ; * 4 bytes/index entry
  713.         mul     cx                      ; = actual byte length of index
  714.         mov     ixbytes,ax
  715.  
  716.         call    format                  ; format the RAMdisk
  717.         jnc     init14                  ; no formatting error, proceed
  718.         mov     dx,offset msg8          ; formatting error, exit
  719.         jmp     init_err
  720.  
  721. init14: call    signon                  ; display program name etc.
  722.  
  723.         mov     es,cs:[envptr]          ; release our environment block
  724.         mov     ah,49h
  725.         int     21h
  726.  
  727.         mov     ah,8                    ; get fixed disk characteristics
  728.         mov     dl,80h                  ; we'll only do physical drive 0
  729.         int     13h                     ; transfer to ROM BIOS
  730.         and     cl,3fh
  731.         mov     maxsec,cl               ; maximum sector number
  732.         mov     maxhead,dh              ; maximum head number
  733.  
  734.         mov     ax,3513h                ; save previous contents
  735.         int     21h                     ; of ROM BIOS disk driver 
  736.         mov     word ptr old13h,bx      ; Int 13H vector
  737.         mov     word ptr old13h+2,es
  738.  
  739.         mov     dx,offset _TEXT:intr    ; set Int 13h vector to point
  740.         mov     ax,2513h                ; to our own handler
  741.         int     21h
  742.                                         ; terminate and stay resident...
  743.         mov     dx,((offset init - offset entry)/16)+11h
  744.         mov     ax,3100h                ; exit with return code = 0
  745.         int     21H                     ; indicating success
  746.  
  747. init_err:                               ; EMM initialization failed,
  748.         push    dx                      ; save specific error message
  749.         mov     si,offset ermsg         ; display error heading
  750.         call    pmsg
  751.         pop     si                      ; display error description
  752.         call    pmsg
  753.         mov     ax,4c01h                ; exit with return code != 0
  754.         int     21h                     ; to indicate an error
  755.  
  756. init    endp
  757.  
  758. ; Initialize cache storage.  Zero out all allocated EMS pages,
  759. ; map the first four pages (which will be used for the cache
  760. ; index) into the page frame, and save that mapping context.
  761.  
  762. format  proc    near
  763.  
  764.         xor     bx,bx                   ; initialize page counter
  765.         mov     es,pframe               ; make EMS page frame addressable
  766.  
  767. fmt1:   cmp     bx,ownedp               ; done with all EMS pages?
  768.         je      fmt2                    ; yes, jump
  769.  
  770.         push    bx                      ; save current page number
  771.         mov     ax,4400h                ; map to physical page 0
  772.         mov     dx,handle               ; get our EMS handle
  773.         int     67h                     ; request mapping by EMM
  774.         pop     bx                      ; restore page number
  775.         or      ah,ah                   ; if bad mapping give up
  776.         jnz     fmt9                    ; (should never happen)
  777.  
  778.         xor     di,di                   ; ES:DI = base of page
  779.         mov     cx,bpp/2                ; page length (words)
  780.         xor     ax,ax                   ; fill page with zeros
  781.         cld     
  782.         rep stosw
  783.  
  784.         inc     bx                      ; increment page and loop
  785.         jmp     fmt1
  786.  
  787. fmt2:                                   ; pre-map all index pages
  788.         mov     ax,4400h                ; initialize physical page
  789.         xor     bx,bx                   ; initialize logical page
  790.         mov     dx,handle               ; EMS handle
  791.  
  792. fmt3:   push    ax                      ; some EMMs bash AL
  793.         int     67h                     ; map this index page into
  794.         or      ah,ah                   ; the page frame
  795.         pop     ax
  796.         jnz     fmt9                    ; jump if mapping failed
  797.         inc     al                      ; next physical page
  798.         inc     bx                      ; next logical page
  799.         cmp     bx,4
  800.         jne     fmt3
  801.  
  802.         mov     ax,4e00h                ; save initial mapping context
  803.         push    ds
  804.         pop     es
  805.         mov     di,offset mymap
  806.         int     67h
  807.         or      ah,ah
  808.         jnz     fmt9                    ; jump if context save failed
  809.  
  810.         clc                             ; exit with CY = 0
  811.         ret                             ; (format successful)
  812.  
  813. fmt9:   stc                             ; exit with CY = 1
  814.         ret                             ; (format failed)
  815.  
  816. format  endp
  817.  
  818. ; Display program title, copyright notice, amounts of
  819. ; installed, available, and allocated expanded memory.
  820.  
  821. signon  proc    near
  822.  
  823.         mov     ax,totalp               ; total installed EMS pages
  824.         mov     dx,16
  825.         mul     dx                      ; pages * 16 = KB
  826.         mov     cx,10
  827.         mov     si,offset ident1
  828.         call    itoa                    ; convert KB to ASCII
  829.  
  830.         mov     ax,availp               ; available EMS pages
  831.         mov     dx,16
  832.         mul     dx                      ; pages * 16 = KB
  833.         mov     cx,10
  834.         mov     si,offset ident2
  835.         call    itoa                    ; convert KB to ASCII
  836.  
  837.         mov     ax,ownedp               ; EMS pages assigned to cache
  838.         mov     dx,16
  839.         mul     dx                      ; pages * 16 = KB
  840.         mov     cx,10
  841.         mov     si,offset ident3
  842.         call    itoa                    ; convert KB to ASCII
  843.  
  844.         mov     si,offset ident         ; display everything
  845.         call    pmsg
  846.         ret                             ; back to caller
  847.  
  848. signon  endp
  849.  
  850. _TEXT   ends
  851.         
  852.         end     entry
  853.  
  854.